<script lang="ts" setup >
import { ref } from "vue";
import { config } from "@/../public/common/config";

const title = ref<string>( "About" );

function readButtonInput( ...args : [ string, number, ...boolean[] ] ) {
  const [ name, version, ...input ] = args;
  return [ name, version, input ];
}

const arr = readButtonInput( "jack", 1.00, true, false );

// 泛型类
class GenericClass<Type> {
  zeroValue : Type;
  add : ( x : Type, y : Type ) => Type;
}

let myGenericNumber = new GenericClass<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function( x, y ) {
  return x + y;
};
myGenericNumber.add( 1, 2 );

//泛型约束
interface Lengthwise {
  length : number;
}

function loggingIdentity<Type extends Lengthwise>( arg : Type ) : Type {
  return arg;
}

interface X {
  [key : string] : number;
}

function getProperty<Type, Key extends keyof Type>( obj : Type, key : Key ) {
  return obj[key];
}

let x : X = {
  a : 1,
  b : 2,
  c : 3,
  d : 4
};

class BeeKeeper {
  hasMask : boolean = true;
}

class ZooKeeper {
  nametag : string = "Mikle";
}

class Animal {
  numLegs : number = 4;
}

class Bee extends Animal {
  override numLegs : number = 6;
  keeper : BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
  keeper : ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>( c : new () => A ) : A {
  return new c();
}

const lion = createInstance( Lion );
const bee = createInstance( Bee );
console.log( "lion", lion.keeper.nametag, lion.numLegs );
console.log( "bee", bee.keeper.hasMask, bee.numLegs );

const MyArray = [
  {
    name : "jack",
    age : 18
  },
  {
    name : "tom",
    age : 16
  },
  {
    name : "lucy",
    age : 19
  },
];
type Person = typeof MyArray[number];
type Age = typeof MyArray[number]["age"];
type Name = typeof MyArray[number]["name"];

const Jack : Person = {
  name : "jack",
  age : 18
}
const age : Age = 18;
const name : Name = "jack";

interface IdLabel {
  id : number;
}

interface NameLabel {
  name : string;
}

type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel;

function createLabel<T extends number | string>( idOrName : T ) : NameOrId<T> {
  return ( typeof idOrName === "number" ? { id : idOrName } : { name : idOrName } ) as NameOrId<T>;
}

let myLabel : NameOrId<number | string> = createLabel( "typescript" );
let myLabel2 : NameOrId<number | string> = createLabel( 1000 );

// type MessageOf<T extends { message : unknown }> = T["message"];
type MessageOf<T> = T extends { message : unknown } ? T["message"] : never;

interface Email {
  message : string;
}

interface Dog {
  bark() : void;
}

type Message = MessageOf<Email>;
type DosMessage = MessageOf<Dog>;

// type Flatten<T> = T extends any[] ? T[number] : T;
// type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
// type Str = Flatten<string[]>;
// type Num = Flatten<number>;
// let strArr : Str[] = [ "1", "2", "3"];
// let num : Num = 1;

type GetReturnType<Type> = Type extends ( ...args : never[] ) => infer ReturnType ? ReturnType : never;
type Num = GetReturnType<() => number>;
type NumArr = GetReturnType<( x : number[] ) => number[]>;
type Str = GetReturnType<( x : string ) => string>;
type Bool = GetReturnType<( a : boolean, b : boolean ) => boolean[]>;
let num : Num = 1;
let str : Str = "1";
let bool : Bool = [ true, false ];

type ToArray<Type> = [ Type ] extends [ any ] ? Type[] : never;
type StrArrToNumArr = ToArray<string | number>;

type OptionFlags<Type> = {
  [Property in keyof Type] : boolean;
}

type Features = {
  darkMode : () => void;
  newUserProfile : () => void;
}
type FeatureOptions = OptionFlags<Features>;

type CreateMutable<Type> = {
  -readonly [Property in keyof Type] : Type[Property];
}
type LockedAccount = {
  readonly id : number;
  readonly name : string;
}

type UnlockedAccount = CreateMutable<LockedAccount>;

type Concrete<Type> = {
  [Property in keyof Type]-? : Type[Property];
}
type MaybeUser = {
  id? : number;
  name? : string;
  age? : number;
}
type User = Concrete<MaybeUser>;

type Getters<Type> = {
  [Property in keyof Type as `get${ Capitalize<string & Property> }`] : () => Type[Property];
}

interface PersonInterface {
  name : string;
  age : number;
  occupation : string;
}

type LazyPerson = Getters<PersonInterface>;

const CreateLazyPerson = ( person : PersonInterface ) : LazyPerson => ( {
  getName : () => person.name,
  getAge : () => person.age,
  getOccupation : () => person.occupation,
} );

const personLazy : PersonInterface = {
  name : "lucy",
  age : 18,
  occupation : "programmer"
}
const lazyInstance = CreateLazyPerson( personLazy );

// type RemoveKindField<Type> = {
//   [Property in keyof Type as Exclude<Property, "kind" | "color">] : Type[Property];
// }

// interface Circle {
//   kind : "circle";
//   radius : number;
//   color : "red";
// }
//
// type KindLessCircle = RemoveKindField<Circle>;
// let circle : KindLessCircle = {
//   radius : 1
// }

type EventConfig <Events extends {kind :string}> = {
  [E in Events as E["kind"]] : (event : E) => void;
}
type SquareEvent = {
  kind : "square",
  x : number;
  y : number;
}
type CircleEvent = {
  kind : "circle",
  radius : number;
}

type Config = EventConfig<SquareEvent | CircleEvent>;


type ExtractPII<Type> = {
  [Property in keyof Type] : Type[Property] extends { pii : true } ? true : false;
}
type DBFields = {
  id : {format : "incrementing"};
  name : {type : "string"; pii : true};
}
type ObjectsNeeding = ExtractPII<DBFields>;


type PropEventSource<Type> = {
  on<Key extends string & keyof Type>
  (eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void) : void;
}
declare function makeWatchedObject<Type>(obj : Type) : Type & PropEventSource<Type>;

class Point {
  x : number = 0;
  y : number = 0;
}

const pt = new Point();


</script >

<template >
  
  <div class="text-center 2lx:text-7xl md:text-5xl sm:text-4xl text-3xl" >{{ title }}</div >
  <div class="text-center" >
    <el-button >change</el-button >
  </div >

</template >

<style >
@import "tailwindcss";

</style >
